﻿using System;
using System.Collections.Generic;
using System.Linq;
using CommonFramework.Serialize.BytesArray;
using NUnit.Framework;

namespace CommonFrameworkTest
{
    [TestFixture]
    public class TestBytesBuffer
    {
        [Test]
        public void CheckIsArray()
        {
            int[] arr = new int[3];
            Assert.That(arr is Array);
        }

        [Test]
        public void CheckIsListType()
        {
            List<float> list = new List<float>();
            Type type = list.GetType();
            
            Assert.That(type.IsGenericType);
            Assert.That(type.GetGenericTypeDefinition()==typeof(List<>));
            Assert.That(type.GetGenericArguments().First()==typeof(float));
        }

        [Test]
        public void CheckIsListObjectType()
        {
            List<object> list = new List<object>();
            Type type = list.GetType();

            Assert.That(type.IsGenericType);
            Assert.That(type.GetGenericTypeDefinition() == typeof(List<>));
            Assert.That(type.GetGenericArguments().First() == typeof(object));

            var obj= Activator.CreateInstance(type.GetGenericArguments().First());
            Console.WriteLine(obj.ToString());
        }

        [Test]
        public void CheckIsDictionaryType()
        {
            Dictionary<float, int> dict = new Dictionary<float, int>();
            Type type = dict.GetType();

            Assert.That(type.IsGenericType);
            Assert.That(type.GetGenericTypeDefinition() == typeof(Dictionary<,>));
            Assert.That(type.GetGenericArguments()[0] == typeof(float));
            Assert.That(type.GetGenericArguments()[1] == typeof(int));
        }

        [Test]
        public void CheckStringIsPrimitiveType()
        {
            string str = "anything";
            Assert.That(str.GetType().IsPrimitive,Is.False);
        }

        [Test]
        public void TestWriteAndRead_Primitive()
        {
            BytesBuffer buffer = new BytesBuffer(BytesBuffer.PER_CHUNK_SIZE);

            int writeSize = 0;
            int readSize = 0;
            List<object> writeVals = new List<object>() { (int)1,//(short)1221,
                (short)1231,(float)1.231,null,(double)4213.24123,(char)'h',(char)'w',
                (string)"gfsdfsvs",(byte)7,(sbyte)-2,null,(ushort)(6523),(bool)true,
                (string)"everything is okkkkkkk~~你好哈",(bool)false,null,
            };

            Random randMaker = new Random();
            BytesWriter writer= buffer.GetWriter();
            BytesReader reader = buffer.GetReader();

            while(writeSize<writeVals.Count || readSize < writeSize)
            {
                if (randMaker.Next() % 2 == 1)
                {
                    if(writeSize < writeVals.Count)
                        writer.Write(writeVals[writeSize++]);
                }
                else if (readSize < writeSize)
                {
                    var writeVal = writeVals[readSize];
                    var readVal= reader.Read(writeVal?.GetType());
                    Assert.That(readVal, Is.EqualTo(writeVal),$"readIndex: {readSize}");
                    readSize++;
                }
            }
        }

        [Test]
        public void TestWriteAndRead_ListContainer()
        {
            BytesBuffer buffer = new BytesBuffer(BytesBuffer.PER_CHUNK_SIZE);

            List<string> writeVals = new List<string>() { 
                (string)"gfsdfsvs",
                (string)"everything is okkkkkkk~~你好哈",
            };

            Random randMaker = new Random();
            BytesWriter writer = buffer.GetWriter();
            writer.Write(writeVals);

            BytesReader reader = buffer.GetReader();
            List<object> readVals = reader.Read(typeof(List<string>)) as List<object>;
                
            Assert.That(writeVals.Count,Is.EqualTo(readVals.Count));
            for (int i = 0; i < writeVals.Count; ++i)
            {
                Assert.That(readVals[i],Is.EqualTo(writeVals[i]));
            }
        }

        [Test]
        public void TestWriteAndRead_DictionaryContainer()
        {
            BytesBuffer buffer = new BytesBuffer(BytesBuffer.PER_CHUNK_SIZE);

            Dictionary<double, string> writeVals = new Dictionary<double, string>();
            Random random = new Random();
            for (int i = 0; i < 10; i++)
            {
                // 生成一个随机的double键
                double key = random.NextDouble() * 1000000;
                // 生成一个随机的字符串值
                string value = $"Value_{random.Next(1, 100)}";
                // 添加键值对到字典中
                writeVals.Add(key, value);
            }

            BytesWriter writer = buffer.GetWriter();
            writer.Write(writeVals);

            BytesReader reader = buffer.GetReader();
            Dictionary<object, object> readVals = reader.Read(typeof(Dictionary<double, string>)) as Dictionary<object,object>;

            Assert.That(writeVals.Count, Is.EqualTo(readVals.Count));
            foreach (var kvp in writeVals)
            {
                Assert.That(readVals.ContainsKey(kvp.Key));
                Assert.That(readVals[kvp.Key],Is.EqualTo(kvp.Value));
            }
        }

        [Test]
        public void TestAutoExtendByWriteLong()
        {
            BytesBuffer buffer = new BytesBuffer(BytesBuffer.PER_CHUNK_SIZE);
            BytesWriter writer = buffer.GetWriter();

            Queue<string> strQue = new Queue<string>();
            Random rand = new Random();
            string longText = "1";
            for (int i = 0; i < 20; ++i)
            {
                if (rand.Next() % 2 == 1)
                {
                    writer.Write(longText);
                    strQue.Enqueue(longText);
                }
                longText = longText + longText;
            }

            BytesReader reader = buffer.GetReader();
            while (strQue.Count > 0)
            {
                string writeVal = strQue.Dequeue();
                object readval = reader.Read(typeof(string));
                Assert.That(readval, Is.EqualTo(writeVal));
            }
        }
    }
}